Coursera - Neural Networks and Deep Learning (week2)

1. Logistic Regression as a Neural Network

Imgur Logistic Regression은 Classification에서 많이 쓰입니다. 위의 예처럼, 주어진 사진이 고양이 사진인지 분류하는 Binary Classification 문제를 보겠습니다. 사진은 RGB픽셀로 이루어져 있습니다. 위의 사진이 64643픽셀이라 하겠습니다. 그림은 간단하게 보여주기 위하여 443으로 하였습니다. 이 모든 픽셀값들을 이용하여 Logistic Regression(줄여서 LR이라 하겠습니다.)을 하려 합니다. LR에서 Input 데이터의 Shape는 열벡터이어야 합니다. 따라서 픽셀값들을 수평으로 나열합니다. (추후에 CNN에서는 이 것을 Flattening이라 합니다.) 이렇게 만든 X는 12288차원의 열벡터과 되고, 이를 입력하여 LR을 통해 Y를 출력합니다.

Imgur 먼저 Logistic Regression에서 사용할 Notation들을 정리하하겠습니다. 입력값 x는 nx차원의 열벡터입니다. y는 1 또는 0(고양인지 아닌지)입니다. m개의 training example이 있으므로 m개의 (x(i), y(i)) 데이터가 있습니다. X는 m개의 x(i)를 수평으로 묶은 벡터입니다. 따라서 X는 nx*b(nx,b)의 shape를 갖습니다. Y는 m개의 y(i)를 수평으로 묶은 행벡터입니다.

Imgur LR에서 얻고자 하는 값은 y hat입니다. 즉 x일 때 y가 1이 될 확률입니다. 이 확률로 우리는 y가 1 또는 0일지 판단할 것입니다. LR에는 두 개의 Parameter가 있습니다. W와 b입니다. LR이 주어진 데이터에서 좋은 결과를 내도록 W와 b를 update할 것 입니다. w는 x와 같은 차원의 열벡터입니다. b는 상수입니다. w와 x를 내적(wT.x)하고 b를 더한 값은 0과 1사이의 값이 아닐 수 있습니다. sigmoid 함수를 사용하여 이 값을 0과 1사이의 값으로 만듭니다. sigmoid함수는 σ(x)라 쓰고, 식은 위의 사진에 나와 있습니다. 증가함수이며 (0, 0.5)에 대칭이고, y값은 x가 작아지면 0에 근사하고, 커지면 1에 근사합니다.

Imgur LR에서 cost function과 loss function에 대해 알아보겠습니다. x값을 입력해 y hat을 구하면 실제 y값과의 차이(error)가 생길것 입니다. 이 error를 나타내는 것이 cost function과 loss function입니다. 따라서 이 함수의 값이 작으면 작을수록 LR의 성능이 좋다고 할 수 있겠죠. 그래서 이 함수들은 후에 LR에서는 cost function을 최소화하도록 두개의 parameter인 w,b를 update합니다. loss function은 하나의 데이터에 대한 error를 나타내는 것이고, cost function은 전체(m개)의 training data에 대한 error입니다. 즉 모든 데이터의 loss function의 평균이 cost function입니다. 고전적인 loss function은 (y-y hat)^2인데 LR에선 모양이 많이 다른 것을 알수 있습니다. LR의 cost function같은 형태를 negative log function이라 합니다. 왜 이러한 함수를 쓰냐면 이 함수는 convex모양(민무늬 토기)이기 때문입니다. 여러 극값(local minimum)을 가지면 최적의 w,b로 update하기가 어렵기 때문입니다. 그럼 아래에서 LR의 cost function에 대해 좀더 알아보겠습니다. Imgur 위를 보면 이러한 cost function의 값이 작을수록 error가 작아지는지 확인할 수 있습니다. y가 1이라면 y hat이 1에 가까워 져야하고, y가 0이라면 y hat은 0에 가까워져야 합니다.(LR은 지도학습이므로 y는 주어집니다.)


그럼이제 w,b를 update하는 방법인 gradient descent에 대해 알아보겠습니다. Imgur 우선 LR의 cost function 그래프를 그려보면 왼쪽위의 3차원 그래프(convex)입니다. 더 높은 차원이겠지만 시각화를 위하여 3차원으로 표현하였습니다. J(w,b)는 데이터가 주어졌을 때 parameter w, b에 대한 cost function입니다. 이 함수값을 최소화 하는 w, b를 찾는 것이 목표입니다.

Imgur 위는 cost function을 2차원으로 표현한 것입니다. Gradient란 경사라 생각면 됩니다. 특정 w일 때의 J(w,b)의 경사(기울기)를 구하고 그 경사를 따라 내려오도록 w를 update 합니다. b도 마찬가지로 update를 합니다. 이 것을 gradient descent (최대경사하강법)이라고 합니다. 즉 특정 parameter에서 cost function의 minimum으로 가는 가장 가파른 경사를 갖는 길을 찾고, 그 길을 따라 (Learning rate - α)만큼 내려가는(w, b를 update) 것입니다. 그럼 최대 경사는 어떻게 구하는지 알아보겠습니다. J(w,b)를 w와 b로 편미분하면 끝! 여기서 기억해야 할 것은 J(w, b)를 w로 편미분한 것(경사)를 dw, b로 편미분 한것을 db같이 표기하는 약속입니다. z로 편미분 하면 dz겠죠?


Imgur 그럼 이제 이 미분을 컴퓨터로 어떻게 구하는지 알아보겠습니다. 가장 중요한건 chain rule입니다! 자세한 설명은 생략하겠습니다. 위를 참고해 주세요! Imgur 이를 LR에서 일반적으로 나타내면 위와 같습니다. sigmoid함수를 미분한 결과도 나와 있는데 모르시면 패스! 고등학교 이과에서는 다루는 내용이라 넘어가겠습니다. 여기서 결론적으로 기억하셔야 할 것은 dw(i) = x(i)dz, db = dz입니다. Imgur

loss fucntion을 미분하는 법을 알았으니, cost function(J(w,b))도 미분할 수 있습니다..! loss를 평균내면 cost이니까요! 위를 참고하시면 됩니다! 즉 cost를 미분한 것은, 각 데이터별로 loss의 경사(gradient)를 구해서(미분) 평균을 내면됩니다. cost의 경사를 구하는 거죠!!

Imgur 그럼 lost function 미분을 computing하는 과정을 살펴보겠습니다. 총 m개의 데이터가 있으가 m번의 loss를 구해서(m번의 loop) 계속 더해가고 마지막에 m으로 나누어 평균을 구하면 끝! loop가 많을 수록 computing시간은 길어지고 학습속도는 느려지게 됩니다. 따라서 loop문을 최소한으로 이용하기 위해 vectorizing을 이용할 것 입니다. 그럼 이제 vectorizing을 살펴보겠습니다.

2. Vectorization

1. Why Use it?

현대의 CPU/GPU는 병렬 처리를 하는데에 최적화 되어 있습니다. 따라서 기존 기계학습 알고리즘을 병렬화 하여 돌릴 수 있다면, 빠른 속도로 작업이 가능할 것입니다.

그럼 Vectorization은 무엇이고, 왜 하는것일까요? Imgur

위 그림과 같이, W 와 X 라는 배열이 있다고 가정 합시다.
예를 들어 Z = W^T^x + b 라는 연산을 할 때, Vectorization이 되어 있지 않다면, for문을 x번 돌려서 Z를 계산 할 것입니다. 하지만, Vectorization되어 있다면, 1번의 Vector계산으로 가능합니다.

하지만, 물론 CPU또는 GPU에서 지원하지 않는다면 공식을 어떻게 세우느냐와 관계 없이 실제 계산은 x번 반복하게 될것 입니다. 그러나, 현대의 CPU는 SIMD(Single Instruction Multiple Data)를 지원하고 있습니다.

SIMD란, 한번의 CPU/GPU 연산에 여러 개의 데이터를 넣을 수 있는 연산자(어셈블리)로 Vector 연산등을 위해 제공되고 있습니다.

우리는 Python 에서 numpy를 통해 해당 연산자를 사용하는 연산을 할 수 있습니다. 아래 그림에서 Neural network를 일반적인 수식과 numpy를 이용한 vector 연산을 한 예시가 있습니다.

Imgur (dot은 Numpy에서 벡터의 내적, 벡터와 행렬의 곱, 행렬곱을 위한 기능)

2 . How to Use it?

Imgur 그림과 같은 경우에, vector v 를 e로 변화 시키고 싶다면, 기존 방식에서는 v vector 를 for loop을 돌며 하나씩 exp 연산을 하게 됩니다. 하지만, vector 연산인 np.exp(v)를 사용하면 하나의 for loop을 삭제 가능합니다.
비슷한 예시로, np.log(v), np.abs(v), np.maximum(v), v**2, 1/v 등의 연산이 제공됩니다.

3. 로지스틱 회귀의 예시

Imgur 로지스틱 회귀는 다음과 같은 연산으로 표현된다.
z^(1)^ = w ^T^x^(1)^ + b, a^(1)^ = , σ(z^(1)^)
는 일반적인 for loop 대신에 vector 연산을 한다면 하나의 연산으로 표현 가능합니다.

z = w ^T^x^(1)^ = np.dot(w,T,x)
z+b = np.dot(w,T,x) + b

Imgur

또한, dz^(1)^ 또한 위 그림과 같이 Vector 연산 가능하며 최종적으로 아래와 같이 연산 가능하다.

Imgur